package com.supor.aiot.home.ui.device.config;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;

import com.android.baseconfig.base.BaseSharedPreferences;
import com.android.baseconfig.common.utils.Logc;
import com.android.baseconfig.common.utils.RxTimerUtil;
import com.android.baseconfig.common.utils.ThreadUtils;
import com.android.baseconfig.common.utils.ToastUtils;
import com.android.baseconfig.common.views.AppBasicDialog;
import com.supor.aiot.common.analysis.AnalysisTool;
import com.supor.aiot.common.analysis.event.BindFailureEvent;
import com.supor.aiot.common.app.AppAgent;
import com.supor.aiot.common.app.Constants;
import com.supor.aiot.common.app.api.DeviceImpl;
import com.supor.aiot.common.entity.ProductType;
import com.supor.aiot.common.entity.RecordBean;
import com.supor.aiot.common.helper.GlobalDataCache;
import com.supor.aiot.common.helper.WifiStationManager;
import com.supor.aiot.common.helper.WsHelper;
import com.supor.aiot.home.R;
import com.supor.aiot.home.bean.PingResult;
import com.supor.aiot.home.helper.APHelper;
import com.supor.aiot.home.helper.DataCache;
import com.supor.aiot.home.helper.WifiConfigHelper;
import com.supor.aiot.home.utils.NetSpeedUtils;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

/**
 * ---------------------------------------------------------------- <br>
 * Copyright (C) 2014-2020, by het, Shenzhen, All rights reserved.  <br>
 * ---------------------------------------------------------------- <br>
 * <p>
 * 描述: 业务数据交互处理 <br>
 * 作者: lei <br>
 * 日期: 2020/12/6 <br>
 */
public class WiFiConfigPresenter {
    private ConfigView configView;
    private Context context;
    /**
     * 绑定类型：0-NFC|1-AP|2-NFC AP
     */
    private int configType = 0;
    private RecordBean recordBean;
    private String routerSsid;
    private String routerBssid;
    private String routerPwd;
    private String productMac = "";
    /**
     * 停止配网
     */
    private boolean stopConfig = false;
    /**
     * 停止queryStatus接口查询
     */
    private boolean stopQueryStatus = false;
    private AppBasicDialog commonDialog;
    public static long testTime = 0;
    public static long allTestTime = 0;
    public static final int QUERY_INTERVAL = 300;
    /**
     * 绑定次数，最多绑定3次
     */
    private int bindCount = 0;
    private APHelper apHelper;
    Handler handler;
    PingResult pingResult;
    /**
     * 路由器连接终端数量
     */
    int connectedNum = 0;
    ProductType.ProductModel productModel;

    public WiFiConfigPresenter(ConfigView configView, Context context) {
        this.configView = configView;
        this.context = context;
        handler = new Handler();
        // ScanResult监听
        apHelper = new APHelper(context, scanResults -> {
            apHelper.unregisterScan();
            if (scanResults == null || scanResults.size() == 0) {
                Logc.e("scanResult list is null");
                configView.onStep1(APHelper.Step.NO_FOUND_AP);
                analysisBindFailure(BindFailureEvent.Value.REASON_AP_NOT_FOUND);
                return;
            }
            if (scanResults.size() > 1) {
                Logc.e("multi scanResult");
                configView.onStep1(APHelper.Step.MULTI_AP);
            } else {
                connectAP(scanResults.get(0));
            }
        });
        // AP配网监听
        WifiConfigHelper.getInstance().setConfigListener((code, mac) -> {
            Logc.i("configResultListener: " + code.name() + ", mac: " + mac);
            if ("CONFIG_ONBOARDING_STOPPED".equalsIgnoreCase(code.name())) {
                return;
            } else if ("CONFIG_DEVICE_CONFIG_SEND_FAILED".equalsIgnoreCase(code.name())) {
                if (!stopConfig) {
                    Logc.i("reconnect...");
                    WifiConfigHelper.getInstance().stopConfig();
                    WifiConfigHelper.getInstance().startConfig(routerSsid, routerBssid, routerPwd);
                    return;
                }
            }
            if (stopConfig) {
                Logc.i("stopConfig--------");
                return;
            }
            if (WifiConfigHelper.getInstance().isConfigSuccess()) {
                return;
            }
            DataCache.CONFIG_START_TIME = System.currentTimeMillis();
            if (mac != null) {
                testTime("config ap");
                String currentWifiSSID = WifiStationManager.getInstance().getCurrentWifiSSID();
                Logc.i("currentWifiSSID: " + currentWifiSSID);

                WifiConfigHelper.getInstance().stopConfig();
                mac = mac.replace(":", "").toUpperCase();
                productMac = mac;
                if (mac.length() != 12) {
                    configView.onStep1(APHelper.Step.FAILURE);
                    ToastUtils.getInstance().showCustomToast("MAC地址不合法");
                    analysisBindFailure(BindFailureEvent.Value.REASON_MAC_INVALID);
                } else {
                    WifiConfigHelper.getInstance().setConfigSuccess(true);
                    configView.onMac(mac);
                    configView.onStep1(APHelper.Step.SUCCESS);
                    // queryStatus(mac);
                }
            } else {
                configView.onStep1(APHelper.Step.FAILURE);
                analysisBindFailure(BindFailureEvent.Value.REASON_MAC_INVALID);
            }
        });
    }

    public void init(Bundle bundle) {
        init(bundle, null);
    }

    public void init(Bundle bundle, ProductType.ProductModel productModel) {
        if (bundle != null) {
            recordBean = bundle.getParcelable(Constants.Key.RECORD_INFO);
            configType = bundle.getInt(Constants.Key.CONFIG_TYPE, 0);
            routerSsid = bundle.getString(Constants.Key.SSID);
            routerBssid = bundle.getString(Constants.Key.BSSID);
            routerPwd = bundle.getString(Constants.Key.PASS);
            // Logc.e("config routerSsid= " + routerSsid + ", routerPwd= " + routerPwd);
        }
        this.productModel = productModel;
        Logc.i("configType: " + configType);
        config(recordBean);
    }

    public void config(RecordBean recordBean) {

        if (configType == 0 || configType == 2) { // NFC/NFC AP
            if (recordBean != null && recordBean.getWifiMac() != null) {
                // 延时是为了跟iOS同步
                handler.postDelayed(() -> {
                    productMac = recordBean.getWifiMac();
                    configView.onMac(productMac);
                    configView.onStep1(APHelper.Step.SUCCESS);
                    testTime = System.currentTimeMillis();
                    allTestTime = System.currentTimeMillis();
                    // queryStatus(recordBean.getWifiMac());
                }, 1500);
            } else {
                analysisBindFailure(BindFailureEvent.Value.REASON_MAC_INVALID);
                configView.onStep1(APHelper.Step.FAILURE);
            }
        } else { // AP
            testTime = System.currentTimeMillis();
            allTestTime = System.currentTimeMillis();
            APConfig();
        }
    }

    private void APConfig() {
        String currentWifiSSID = WifiStationManager.getInstance().getCurrentWifiSSID();
        if (currentWifiSSID != null && currentWifiSSID.startsWith(Constants.SUPOR_AP_PREFIX)) {
            Logc.i("already connected ap, start config ssid: " + routerSsid + ", pass: "
                    + routerPwd + ", ap: " + currentWifiSSID);
            WifiConfigHelper.getInstance().startConfig(routerSsid, routerBssid, routerPwd);
            return;
        }

        apHelper.getScanResultList(Constants.SUPOR_AP_PREFIX);
    }

    private void connectAP(ScanResult scanResult) {
        Logc.i("start connect ap---------routerSsid= " + routerSsid + ", routerPwd= " + routerPwd
                + ", ap: " + scanResult.SSID);
        apHelper.connectAP(scanResult, success -> {
            if (stopConfig) {
                Logc.i("stopConfig--------");
                return;
            }
            if (success) {
                Logc.i("connect ap success: start config, routerSsid= "
                        + routerSsid, ", routerPwd= " + routerPwd);
                testTime("connect ap");
                WifiConfigHelper.getInstance().startConfig(routerSsid, routerBssid, routerPwd);
            } else {
                Logc.e("onResult: connect ap failed");
                configView.onStep1(APHelper.Step.CONN_AP_FAILURE);
                analysisBindFailure(BindFailureEvent.Value.REASON_AP_DISCONNECTED);
            }
        });
    }

    /**
     * 查询设备在线离线状态，离线则一直请求，在线则调用绑定接口，对应后台机智云snoti更新Redis设备在线状态
     *
     * <br>配网针对设备正常联网而App配网失败的情况：正常配网30秒结束后，
     * <br>再通过后台直接调用机智云企业API去查询设备在线状态并返回，如果在线就进行绑定，失败再走失败流程，过程为10秒；
     *
     * @param mac 设备MAC地址
     */
    @SuppressLint("CheckResult")
    public void queryStatus(String mac) {
        Logc.i("queryStatus mac: " + mac);
        DeviceImpl.getInstance().queryStatus(mac).subscribe(result -> {
            if (stopQueryStatus) {
                Logc.d("stopQueryStatus--------");
                // todo for api query
                // apiQueryStatus(mac);
                analysisBindFailure(BindFailureEvent.Value.REASON_QUERY_FAILURE, "snoti_device_offline", false);
                return;
            }
            if ("on".equalsIgnoreCase(result.data)) {
                testTime("wifi status on");
                bind(mac);
            } else if ("off".equalsIgnoreCase(result.data)) {
                ThreadUtils.execute(() -> queryStatus(mac), QUERY_INTERVAL);
            }
        }, throwable -> {
            Logc.e("queryStatus error: " + throwable.getMessage());
            // if (throwable instanceof HttpException) {
            //     HttpException exception = (HttpException) throwable;
            //     if (exception.code() == 403) {
            //         configView.onStep3(null);
            //         analysisBindFailure(BindFailureEvent.Value.REASON_QUERY_FAILURE);
            //         ToastUtils.getInstance().showCustomToast("queryStatus: 签名失败或者应用ID错误");
            //         return;
            //     } else if (exception.code() == 401) {
            //         ToastUtils.getInstance().showCustomToast("请重新登录");
            //         configView.onStep3(null);
            //         setStopConfig(true);
            //         configView.onCloseAccount();
            //         analysisBindFailure(BindFailureEvent.Value.REASON_NOT_LOGIN);
            //         return;
            //     }
            // }
            if (!stopQueryStatus) {
                ThreadUtils.execute(() -> queryStatus(mac), QUERY_INTERVAL);
            } else {
                analysisBindFailure(BindFailureEvent.Value.REASON_QUERY_FAILURE, throwable.getMessage());
                // todo for api query
                // apiQueryStatus(mac);
            }
        });
    }

    /**
     * 查询设备在线离线状态，在线则调用绑定接口，对应后台机智云企业API查询设备状态
     *
     * @param mac 设备MAC地址
     */
    @SuppressLint("CheckResult")
    public void apiQueryStatus(String mac) {
        Logc.i("apiQueryStatus mac: " + mac);
        DeviceImpl.getInstance().apiQueryStatus(mac).subscribe(result -> {
            if (stopConfig) {
                analysisBindFailure(BindFailureEvent.Value.REASON_QUERY_FAILURE, "api_device_offline: " + result.data);
                Logc.i("stopConfig--------");
                return;
            }
            // 只做查询
            // if ("on".equalsIgnoreCase(result.data)) {
            //     testTime("wifi status on");
            //     bind(mac);
            // } else if ("off".equalsIgnoreCase(result.data)) {
                ThreadUtils.execute(() -> apiQueryStatus(mac), QUERY_INTERVAL * 4);
            // }
        }, throwable -> {
            Logc.e("apiQueryStatus error: " + throwable.getMessage());

            if (!stopConfig) {
                ThreadUtils.execute(() -> apiQueryStatus(mac), QUERY_INTERVAL * 4);
            } else {
                analysisBindFailure(BindFailureEvent.Value.REASON_QUERY_FAILURE, "apiQuery: " + throwable.getMessage());
                // ToastUtils.getInstance().showCustomToast("queryStatus: " + throwable.getMessage());
            }
        });
    }

    /**
     * 设备绑定接口，成功会返回机智云设备信息
     *
     * @param mac 设备MAC地址
     */
    @SuppressLint("CheckResult")
    public void bind(String mac) {
        Map<String, String> map = new HashMap<>();
        map.put("mac", mac);
        if (productModel != null) {
            map.put("productModel", productModel.modelId);
            map.put("bindType", "wifi");
        }
        map.put("thirdType", "Gizwits");
        DeviceImpl.getInstance().bind(map).subscribe(result -> {
            Logc.i("bind result: " + result.toString());
            if (stopConfig) {
                Logc.i("stopConfig--------");
                return;
            }
            if (result.isSuccess() && result.data != null) {
                WsHelper.getInstance().init(AppAgent.getApp(), true);
                GlobalDataCache.getBindDevice();
                sendWifiType(mac);
                JSONObject jsonObject = new JSONObject(result.data);
                jsonObject.put(Constants.Key.MAC, mac);
                configView.onStep3(jsonObject.toString());
                BaseSharedPreferences.setString(context, Constants.Key.param_bindInfo, jsonObject.toString());
                Logc.i("lllll-bind success cost: " + ((System.currentTimeMillis() - allTestTime) / 1000f));
                // pushAppToken(mac);
            } else {
                if (!checkLoginStatus(result.status)) {
                    return;
                }
                ThreadUtils.execute(() -> bind(mac), QUERY_INTERVAL);
                // retryBind(mac, null);
            }
        }, throwable -> {
            Logc.e("bind error: " + throwable.getMessage());
            if (!stopConfig) {
                ThreadUtils.execute(() -> bind(mac), QUERY_INTERVAL);
                // retryBind(mac, throwable);
            } else {
                analysisBindFailure(BindFailureEvent.Value.REASON_UNBIND, throwable.getMessage());
                ToastUtils.getInstance().showCustomToast("bind: " + throwable.getMessage());
            }
        });
    }

    private boolean checkLoginStatus(int status) {
        // 用户不存在
        if (status == 1009) {
            ToastUtils.getInstance().showCustomToast("用户已被注销，请重新登录");
            setStopConfig(true);
            configView.onCloseAccount();
            return false;
        }
        return true;
    }

    /**
     * 绑定完成后延时两秒发送wifiType=1
     *
     * @param mac
     */
    public void sendWifiType(String mac) {
        ThreadUtils.execute(() -> {
            Logc.e("sendWifiType: ");
            if (WsHelper.getInstance().isCloseConnectionWebsocket()) {
                Logc.e("isCloseConnectionWebsocket: true ");
                sendWifiType(mac);
                return;
            }
            com.alibaba.fastjson.JSONObject object = new com.alibaba.fastjson.JSONObject();
            object.put("wifiType", 1);
            if (!WsHelper.getInstance().c2sWrite(mac, null, object.toJSONString())){
                sendWifiType(mac);
            }

        }, 2000);
    }

    /**
     * 绑定重试，3次
     *
     * @param mac 设备MAC地址
     * @param throwable
     */
    private void retryBind(String mac, Throwable throwable) {
        if (bindCount < 3) {
            bindCount++;
            bind(mac);
        } else {
            configView.onStep3(null);
            ToastUtils.getInstance().showCustomToast("retryBind: " + (throwable == null ? "null" :
                    throwable.getMessage()));
            bindCount = 0;
            analysisBindFailure(BindFailureEvent.Value.REASON_UNBIND);
        }
    }

    /**
     *上报绑定结果
     *
     * @param productMac 设备MAC地址
     * @param isSuccess 配网是否成功: 1-成功|0-失败
     */
    @SuppressLint("CheckResult")
    public void pushBindResult(String productMac, String isSuccess) {
        int configTime = (int) (System.currentTimeMillis() - DataCache.CONFIG_START_TIME);
        DeviceImpl.getInstance().pushBindResult(GlobalDataCache.getUniqueId(), productMac,
                (configType == 0 ? "2" : "3"), configTime, isSuccess).subscribe(result -> {
            Logc.i("pushBindResult result: " + result.toString());
        }, throwable -> {
            Logc.e("pushBindResult error: " + throwable.getMessage());
        });
    }

    private void testTime(String tag) {
        Logc.i("lllll-" + tag + " cost: " + ((System.currentTimeMillis() - testTime) / 1000f));
        testTime = System.currentTimeMillis();
    }

    public void showDialog(String title, String msg, DialogInterface.OnClickListener noCallback,
                           DialogInterface.OnClickListener waitCallback) {
        if (commonDialog != null && commonDialog.isShowing()) {
            commonDialog.dismiss();
        }
        AppBasicDialog.Builder builder = new AppBasicDialog.Builder(context, false);
        builder.setTitle(title);
        builder.setMessage(msg);
        builder.setNegativeButton(R.string.bind_give_up_add, noCallback);
        builder.setPositiveButton(R.string.bind_wait, waitCallback);
        commonDialog = builder.create();
        commonDialog.setCancelable(false);
        commonDialog.show();
    }

    public void closeDialog() {
        if (commonDialog != null && commonDialog.isShowing()) {
            commonDialog.dismiss();
        }
    }

    public boolean isDialogShow() {
        return commonDialog != null && commonDialog.isShowing();
    }

    /**
     * 开始倒计时
     */
    public void startTimer() {
        RxTimerUtil.countdown(30, number -> {
            if (configView != null) {
                if (number >= 0) {
                    configView.countdown((int) number);
                    // todo for api query
                    // if (number <= 10) {
                    //     stopQueryStatus = true;
                    // }

                    // 15s还未完成初始化网络速率并检测路由器终端数量
                    // if (number == 15) {
                    //     NetSpeedUtils.getRxNetSpeed(context);
                    //     ThreadUtils.execute(() -> connectedNum = NetSpeedUtils.getWifiConnectedNum(context));
                    // }
                } else {
                    configView.onStep3(null);
                    // analysisBindFailure(BindFailureEvent.Value.REASON_OFFLINE, "countdown stop");
                }
            }
        });
    }

    /**
     * 停止倒计时
     */
    public void stopTimer() {
        RxTimerUtil.cancelCountdown();
    }

    /**
     * 检测网络是否能连外网，Ping机智云域名，只要ping网一次成功就进下一步，连续ping网5s超时表示失败
     */
    public void checkNetAvailable() {
        // 初始化当前速率
        NetSpeedUtils.getRxNetSpeed(context);
        // WiFi不能连网时ping的时间不确定，定时6s网络检测失败
        handler.postDelayed(() -> {
            WiFiConfigPresenter.this.pingResult = new PingResult();
            configView.onStep2(1, pingResult);
        }, 6000);
        ThreadUtils.execute(() -> NetSpeedUtils.ping("www.baidu.com", 8, 5,
                new NetSpeedUtils.PingCallback() {
                    @Override
                    public void onPing(int count) {
                        if (count == 1) {
                            Logc.d("onPing: ");
                            handler.removeCallbacksAndMessages(null);
                            configView.onStep2(0, null);
                        }
                    }

                    @Override
                    public void onPingResult(PingResult pingResult) {
                        Logc.d("onPingResult: " + pingResult.toString());
                        handler.removeCallbacksAndMessages(null);
                        WiFiConfigPresenter.this.pingResult = pingResult;
                        configView.onStep2(1, pingResult);
                    }
                }));
    }

    public void setStopConfig(boolean stopConfig) {
        this.stopConfig = stopConfig;
        this.stopQueryStatus = stopConfig;
    }

    public void onDestroy() {
        stopTimer();
        stopConfig = true;
        stopQueryStatus = true;
        WifiConfigHelper.getInstance().stopConfig();
        apHelper.destroy();
    }

    public void analysisBindFailure(String reason) {
        analysisBindFailure(reason, null);
    }

    public void analysisBindFailure(String reason, String msg) {
        analysisBindFailure(reason, msg, true);
    }

    public void analysisBindFailure(String reason, String msg, boolean updateNow) {
        HashMap<String, String> params = new HashMap<>();
        params.put(BindFailureEvent.Param.BIND_TYPE, configType == 0 ?
                BindFailureEvent.Value.BIND_TYPE_NFC : BindFailureEvent.Value.BIND_TYPE_AP);
        // params.put(BindFailureEvent.Param.USER_ID, DataCache.userInfo.getBossUserId());
        params.put(BindFailureEvent.Param.WIFI_NAME, routerSsid);
        params.put(BindFailureEvent.Param.PRODUCT_MAC, productMac);
        params.put(BindFailureEvent.Param.BIND_STAGE, BindFailureEvent.Value.STAGE_BINDING);
        params.put(BindFailureEvent.Param.FAILURE_REASON, reason);
        if (!TextUtils.isEmpty(msg)) {
            params.put(BindFailureEvent.Param.FAILURE_MSG, msg);
        }
        if (pingResult != null) {
            params.put(BindFailureEvent.Param.NETWORK_PACKETLOSS, pingResult.loss);
            params.put(BindFailureEvent.Param.NETWORK_DELAY, pingResult.avgRtt);
            params.put(BindFailureEvent.Param.NETWORK_DEVICES, String.valueOf(connectedNum));
            WifiInfo wifiInfo = WifiStationManager.getInstance().getConnectionWifiInfo();
            if (wifiInfo != null) {
                params.put(BindFailureEvent.Param.NETWORK_RSSI, String.valueOf(wifiInfo.getRssi()));
            }
            params.put(BindFailureEvent.Param.NETWORK_RATE, String.valueOf(NetSpeedUtils.getRxNetSpeed(context)));
        }
        AnalysisTool.bindFailureEvent(params, updateNow);
    }

    public interface ConfigView {
        /**
         * 倒计时
         *
         * @param count 倒计时数
         */
        void countdown(int count);

        /**
         * 步骤1完成状态
         *
         * @param result
         */
        void onStep1(APHelper.Step result);

        /**
         * 步骤2完成状态（检测网络）
         *
         * @param result 0-正常|1-异常
         * @param pingResult ping result
         */
        void onStep2(int result, PingResult pingResult);

        /**
         * 步骤3完成状态
         *
         * @param bindData 不为空-成功|等于空-失败
         */
        void onStep3(String bindData);

        /**
         * user close account
         */
        void onCloseAccount();

        /**
         * mac
         */
        void onMac(String mac);
    }
}
